#!/usr/bin/env python3

import socket
import os
import signal
import sys
import select

line = 1

def msg(s):
    print('\033[1;1H\033[2K%s' % s, end='', flush=True)

def outRecvData(sd, name='服务端'):
    global line

    data, addr = sd.recvfrom(1024)

    data = data.decode()

    if data == 'exit':
        return None

    print("\033[s\033[%d;1H\033[2K%s接受到(%s): %s\033[u"
                % (line, name, addr[0], data), end='', flush=True)
    line += 1
    if line == 11:
        line = 1

    return addr

def myExit(sig, stack):
    print("\033[15;1H\033[2K", end='', flush=True)
    os._exit(0)

def chatHandle(sd, addr, name="服务端"):
    if os.fork() == 0:
        while outRecvData(sd, name):
            pass
    else:
        while True:
            data = input("\033[13;1H\033[2K%s发送: " % name)
            sd.sendto(data.encode(), addr)
            if data == 'exit':
                break

    sd.close()
    os.kill(0, signal.SIGTERM)

def main():
    #  没有参数: 9000 0.0.0.0
    #  一个参数: 绑定端口号
    #  二个参数: 服务器口号 服务器IP
    argc = len(sys.argv)

    port = int(sys.argv[1]) if argc == 2 else 9000
    ip = sys.argv[2] if argc == 3 else "0.0.0.0"

    addr = (ip, port)

    print('\033[2J', end='', flush=True)

    signal.signal(signal.SIGTERM, myExit)
    sd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    #  开启广播功能
    sd.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    #  发送查找服务器的广播包
    sd.sendto('请求链接'.encode('utf-8'), ('255.255.255.255', port))
    msg("正在查找服务器.....")
    r, w, x = select.select([sd.fileno()], [], [], 3)

    if r:  #有服务器
        msg("找到服务器(%s), 准备开始通信..." % addr[0])
        data, addr = sd.recvfrom(1024)
        name = '客户端'
    else: #无服务器
        msg("没有查找到服务器,准备创建服务器....")
        sd.close()
        sd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sd.bind(addr)
        msg("正在等待客户端发送数据.....")
        data, addr = sd.recvfrom(1024)
        msg("接受到 %s 客户端的请求连接...." % addr[0])
        sd.close()
        sd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sd.sendto('请求通过'.encode('utf-8'), addr)
        name = '服务端'

    chatHandle(sd, addr, name)

if __name__ == "__main__":
    main()
